﻿using FasterBuild;
using FileSynchronization.Model;
using FileSynchronization.SettingModel;
using Microsoft.AspNetCore.Mvc;

namespace FileSynchronization.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    [Route("FileAsync")]
    [ApiController]
    public class FileAsyncController : ControllerBase
    {
        private SyncSetting _syncSetting;

        private ILog _log;

        private string _basePath = $"{AppDomain.CurrentDomain.BaseDirectory}\\Uploads";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="log"></param>
        /// <param name="syncSetting"></param>
        public FileAsyncController(ILog log, SyncSetting syncSetting)
        {
            _syncSetting = syncSetting;
            _log = log;
        }

        /// <summary>
        /// 上传包文件(支持分片)
        /// </summary>
        /// <param name="Type"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("UploadPackFile/{Type}")]
        public async Task UploadPackFile([FromRoute] SyncType Type, [FromForm] UploadModel model)
        {
            var file = model.file;
            var fileName = Path.GetFileName(file.FileName);
            var basePath = $"{_basePath}\\{Type}\\{model.baseDir}";

            //分片
            if (!string.IsNullOrEmpty(model.guid))
            {
                fileName = fileName + $".chunk{(model.chunk >= 10 ? model.chunk.ToString() : $"0{model.chunk}")}";
                basePath = $"{_basePath}\\Temp\\{model.guid}";
            }

            //正常上传
            if (!Directory.Exists(basePath))
                Directory.CreateDirectory(basePath);

            var filePath = Path.Combine(basePath, fileName);

            using (var stream = new FileStream(filePath, FileMode.OpenOrCreate))
            {
                await file.CopyToAsync(stream);
            }

            //需要合并分片操作
            if (!string.IsNullOrEmpty(model.guid) && model.chunk == model.chunks)
            {
                var allChunkFiles = Directory.GetFiles(basePath);
                allChunkFiles = allChunkFiles.OrderBy(s => s).ToArray();
                using (var mergeStream = new FileStream(Path.Combine($"{_basePath}/{Type}/{model.baseDir}", Path.GetFileName(file.FileName)), FileMode.Create))
                {
                    BinaryWriter binaryWriter = new BinaryWriter(mergeStream);
                    foreach (var chunkFile in allChunkFiles)
                    {
                        FileInfo fileInfo = new FileInfo(chunkFile);
                        var stream = fileInfo.OpenRead();
                        BinaryReader binaryReader = new BinaryReader(stream);
                        binaryWriter.Write(binaryReader.ReadBytes((int)stream.Length));
                        binaryReader.Close();
                        stream.Close();
                        binaryReader.Dispose();
                        stream.Dispose();
                    }
                    binaryWriter.Close();
                    binaryWriter.Dispose();
                }
                Directory.Delete(basePath, true);
            }
        }

        /// <summary>
        /// 开启同步
        /// </summary>
        /// <param name="Type"></param>
        /// <returns></returns>
        [HttpPost("SyncPackFile/{Type}")]
        public void SyncPackFile([FromRoute] SyncType Type)
        {
            var basePath = $"{_basePath}\\{Type}";
            var bakPath = $"{_basePath}\\Bak\\{Type}\\{DateTime.Now:yyyyMMdd_HHmmss}";

            if (!Directory.Exists(basePath))
                throw new OutPutException("未找到源文件夹");

            var typeSetting = _syncSetting.Items.Where(s => s.Type == Type).FirstOrDefault();
            if (typeSetting is null)
                throw new OutPutException("未找到相关配置");

            if (!Directory.Exists(typeSetting.ApplicationLocation))
                throw new OutPutException("未找到目标文件夹");

            bool appPoolStop = false;
            if (!string.IsNullOrEmpty(typeSetting.ApplicationAppPool))
            {
                CommonHelper.RunCmd($"C:\\Windows\\System32\\inetsrv\\appcmd.exe stop apppool /apppool.name:\"{typeSetting.ApplicationAppPool}\"", out var output);
                if (output.Contains("已成功停止"))
                    appPoolStop = true;
                else
                    throw new OutPutException($"‘{typeSetting.ApplicationAppPool}’应用池未能成功停止");
            }

            //文件同步
            string[] files = Directory.GetFiles(basePath, "*");
            if (files is not null && files.Length > 0)
            {
                if (!Directory.Exists(bakPath))
                    Directory.CreateDirectory(bakPath);

                foreach (var file in files)
                {
                    var fileName = Path.GetFileName(file);
                    var destFilePath = Path.Combine(typeSetting.ApplicationLocation, fileName);
                    if (System.IO.File.Exists(destFilePath))
                    {
                        // 备份 从程序目录复制到bak
                        System.IO.File.Copy(destFilePath, Path.Combine(bakPath, fileName), true);
                    }

                    //从发布目录同步到程序目录
                    System.IO.File.Copy(file, destFilePath, true);
                }
            }

            //文件夹同步
            string[] directories = Directory.GetDirectories(basePath, "*");
            if (files is not null && files.Length > 0)
            {
                foreach (var directory in directories)
                {
                    var directoryName = Path.GetFileName(directory);
                    var destDirectoryPath = Path.Combine(typeSetting.ApplicationLocation, directoryName);
                    if (Directory.Exists(destDirectoryPath))
                    {
                        // 备份 从程序目录复制到bak
                        CommonHelper.CopyDirectory(destDirectoryPath, Path.Combine(bakPath, directoryName));
                    }
                    //同步文件
                    CommonHelper.CopyDirectory(directory, destDirectoryPath);
                }
            }

            if (appPoolStop)
            {
                //五秒后再重启 怕应用池还未回收完成
                Thread.Sleep(5000);
                CommonHelper.RunCmd($"C:\\Windows\\System32\\inetsrv\\appcmd.exe start apppool /apppool.name:\"{typeSetting.ApplicationAppPool}\"", out var output);
            }
        }

        /// <summary>
        /// 清空包文件
        /// </summary>
        /// <param name="Type"></param>
        [HttpPost("ClearPackFile/{Type}")]
        public void ClearPackFile([FromRoute] SyncType Type)
        {
            var basePath = $"{_basePath}/{Type}";

            //文件
            string[] files = Directory.GetFiles(basePath, "*");
            if (files is not null && files.Length > 0)
            {
                foreach (var item in files)
                {
                    System.IO.File.Delete(item);
                }
            }

            //文件夹
            string[] directories = Directory.GetDirectories(basePath, "*");
            if (directories is not null && directories.Length > 0)
            {
                foreach (var item in directories)
                {
                    Directory.Delete(item, true);
                }
            }
        }

        /// <summary>
        /// 删除备份
        /// </summary>
        /// <param name="Type"></param>
        [HttpPost("RemovePackBak/{Type}")]
        public void RemovePackBak([FromRoute] SyncType Type)
        {
            var bakBasePath = $"{_basePath}\\Bak\\{Type}";
            var bakDay = 10;

            if (Directory.Exists(bakBasePath))
            {
                var bakDirList = Directory.GetDirectories(bakBasePath, "*");

                if (bakDirList is null || bakDirList.Length <= 0)
                    return;

                //排序 如果不超过10个备份 就不处理
                bakDirList = bakDirList.OrderBy(s => s).ToArray();
                if (bakDirList.Length <= bakDay) return;

                //取出备份总数-10个备份进行删除
                bakDirList.Take(bakDirList.Length - bakDay).ToList()
                    .ForEach(deleteBakPath => Directory.Delete(deleteBakPath, true));
            }
        }
    }
}
